package com.itfreer.gis.map.style;

import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.DefaultTransactionDefinition;

import com.alibaba.dubbo.config.annotation.Service;
import com.itfreer.data.config.ConfigVersionService;
import com.itfreer.form.api.BaseDao;
import com.itfreer.form.api.BaseServiceImp;
import com.itfreer.form.api.DataInputResult;
import com.itfreer.form.api.dictionary.DictionaryEntity;
import com.itfreer.form.api.dictionary.DictionaryService;
import com.itfreer.gis.map.style.entity.MapStyleEntity;
import com.itfreer.gis.map.style.entity.MapStyleLayerEntity;
import com.itfreer.gis.map.style.entity.MapStyleSourceEntity;
import com.itfreer.gis.map.style.transfer.FmStyleTransfer;
import com.itfreer.utils.BaseHost;
import com.itfreer.utils.ResponseEntity;
import com.itfreer.utils.SpringContext;
import com.itfreer.utils.file.FileMeta;
import com.itfreer.utils.file.FilePara;
import com.itfreer.utils.json.JsonUtils;
import com.itfreer.gis.map.style.dao.MapStyleDao;
import com.itfreer.gis.map.style.dao.MapStyleLayerDao;
import com.itfreer.gis.map.style.dao.MapStyleSourceDao;

/**
 * 定义我的样式实现类
 */
@Component
@Service(interfaceClass = MapStyleService.class, path = "styles")
public class MapStyleServiceImp extends BaseServiceImp<MapStyleEntity> implements MapStyleService {

    @Autowired
    private MapStyleDao dao;
    @Autowired
    private BaseHost baseHost;
    @Autowired
    private DictionaryService dictionaryManage;

    @Autowired
    private MapStyleLayerDao layerDao;
    @Autowired
    private MapStyleSourceDao sourceDao;

    @Autowired(required = false)
    private ConfigVersionService configVersionService;

    // 简单数据缓存对象
    private Map<String, MapStyle> caches = new HashMap<>();

    @Override
    protected BaseDao<MapStyleEntity> getDao() {
        return dao;
    }

    @Override
    public MapStyle getLayers(String id, StyleParas paras) {
        return getStyleData(id, paras);
    }

    @Override
    public Map<String, Object> getStyle(String id, StyleParas paras) {
        MapStyle styleEntity = getStyleData(id, paras);
        return assemStyle(styleEntity);
    }

    /**
     * 获取mb转换后的方案 此方法特为android原生提供，暂不支持方案的适配
     */
    @Override
    public Map<String, Object> mbstyle(String id) {
        StyleParas paras = new StyleParas();
        paras.setBrowser("1");
        paras.setTerminal("2");
        paras.setKernel("mapboxgl");
        Map<String, Object> style = getStyle(id, paras);
        return FmStyleTransfer.transferEx(style, baseHost);
    }

    @Override
    public Map<String, Object> offlineStyle(String id) {
        // TODO Auto-generated method stub
        StyleParas paras = new StyleParas();
        paras.setBrowser("1");
        paras.setTerminal("2");
        paras.setKernel("mapboxgl");
        Map<String, Object> style = getStyle(id, paras);
        return FmStyleTransfer.transferEx(style, baseHost);
    }

    /**
     * 获取android原生下的方案数据
     */
    @Override
    public MapStyle datas(String id) {
        StyleParas paras = new StyleParas();
        paras.setBrowser("1");
        paras.setTerminal("2");
        paras.setKernel("mapboxgl");
        return getStyleData(id, paras);
    }

    @SuppressWarnings("unchecked")
    private Map<String, Object> assemStyle(MapStyle styleEntity) {
        DictionaryEntity item = dictionaryManage.getDictionary("p_sprite_directory", styleEntity.getSprite());
        FileMeta[] sprites = (FileMeta[]) item.getOther().get("sprite");
        FilePara filePara = SpringContext.getBean(FilePara.class);
        String url = filePara.getDownloadUrl(sprites[0]);
        url = url.replace("@2x", "").replace(".png", "").replace(".json", "");

        Map<String, Object> style = new HashMap<String, Object>();
        style.put("version", 8);
        style.put("sprite", url);
        style.put("glyphs", "fm://fonts/{fontstack}/{range}");
        style.put("sources", assemSources(styleEntity.getSources()));
        style.put("layers", assemLayers(styleEntity.getLayers()));

        String propertys = styleEntity.getPropertys();
        if (null != propertys && !"".equals(propertys)) {
            Map<String, Object> propertyJson = JsonUtils.toBean(propertys, Map.class);
            if (null != propertyJson && !propertyJson.isEmpty()) {
                // 加入其它属性值
                style.putAll(propertyJson);
            }
        }
        return style;
    }

    /**
     * 组装sources属性的值
     *
     * @param sourcesEntitys
     * @return
     */
    private Map<String, Object> assemSources(Set<MapStyleSource> sourcesEntitys) {
        // 定义存储每个sources的详情的Map对象
        Map<String, Object> sourcesInfoMap = new HashMap<String, Object>();
        for (MapStyleSource sourceEntity : sourcesEntitys) {
            sourcesInfoMap.put(sourceEntity.getName(), assemSourceInfo(sourceEntity));
        }
        return sourcesInfoMap;
    }

    /**
     * 组装每个source的详细信息
     *
     * @param sourceEntity
     * @return
     */
    @SuppressWarnings("unchecked")
    private Map<String, Object> assemSourceInfo(MapStyleSource sourceEntity) {
        Map<String, Object> infoMap = new HashMap<String, Object>();
        String sourcePopertys = sourceEntity.getPropertys();
        if (null != sourcePopertys && !("".equals(sourcePopertys))) {
            Map<String, Object> sourcePopertysJson = JsonUtils.toBean(sourcePopertys, Map.class);
            if (null != sourcePopertysJson && !sourcePopertysJson.isEmpty()) {
                // 加入其它属性值
                infoMap.putAll(sourcePopertysJson);
            }
        }

        // 获取数据源类型
        String type = sourceEntity.getType();
        infoMap.put("type", type);

        // 获取数据源服务类型
        String serverType = sourceEntity.getServerType();
        if (null != serverType && !("".equals(serverType)) && !("9999".equals(serverType)) && !(serverType.length() == 3)) {
            infoMap.put("serverType", serverType);
        }

        return infoMap;
    }

    /**
     * 组装Layers属性的值
     *
     * @param sourcesEntitys
     * @return
     */
    private List<Map<String, Object>> assemLayers(Set<MapStyleLayer> layersEntitys) {
        if (null == layersEntitys || layersEntitys.size() < 1) {
            return null;
        }

        List<Map<String, Object>> layersList = new ArrayList<Map<String, Object>>();
        for (MapStyleLayer layerEntity : layersEntitys) {
            if ("2".equals(layerEntity.getGroup())) {// 图层节点处理
                layersList.add(assemLayerInfo(layerEntity));
            }
        }
        return layersList;
    }

    @SuppressWarnings("unchecked")
    private Map<String, Object> assemLayerInfo(MapStyleLayer layerEntity) {
        Map<String, Object> layerMap = new HashMap<String, Object>();
        layerMap.put("id", layerEntity.getId());
        layerMap.put("type", layerEntity.getType());
        if (!layerEntity.getType().equals("background")) {
            layerMap.put("source-layer", layerEntity.getSourceLayer() != null ? layerEntity.getSourceLayer() : "");
            layerMap.put("source", layerEntity.getSource());
        }

        String layout = layerEntity.getLayout();
        if (null == layout || "".equals(layout)) {
            layerMap.put("layout", JsonUtils.toBean("{}", Object.class));
        } else {
            layerMap.put("layout", JsonUtils.toBean(layout, Map.class));
        }

        String paint = layerEntity.getPaint();
        if (null == paint || "".equals(paint)) {
            layerMap.put("paint", JsonUtils.toBean("{}", Object.class));
        } else {
            layerMap.put("paint", JsonUtils.toBean(paint, Map.class));
        }

        String filter = layerEntity.getFilter();
        if (null != filter && !"".equals(filter)) {
            layerMap.putAll(JsonUtils.toBean(layerEntity.getFilter(), Map.class));
        }

        Float maxzoom = layerEntity.getMaxzoom();
        if (null != maxzoom && maxzoom.floatValue() > 0) {
            layerMap.put("maxzoom", maxzoom);
        }

        Float minzoom = layerEntity.getMinzoom();
        if (null != minzoom) {
            if (minzoom == 0.0f) {
                layerMap.put("minzoom", 0);
            } else {
                layerMap.put("minzoom", minzoom);
            }
        }

        String propertys = layerEntity.getPropertys();
        if (null != propertys && !("".equals(propertys))) {
            Map<String, Object> sourcePropertysJson = JsonUtils.toBean(propertys, Map.class);
            if (null != sourcePropertysJson && !sourcePropertysJson.isEmpty()) {
                // 加入其它属性值
                layerMap.putAll(sourcePropertysJson);
            }
        }

        return layerMap;
    }

    /**
     * 根据ID、浏览器、终端获取数据
     *
     * @return
     */
    private MapStyle getStyleData(String id, StyleParas paras) {
        String key = id;
        if (paras.getBrowser() != null) {
            key += "_" + paras.getBrowser();
        }
        if (paras.getKernel() != null) {
            key += "_" + paras.getKernel();
        }
        if (paras.getMemory() != null) {
            key += "_" + paras.getMemory();
        }
        if (paras.getTerminal() != null) {
            key += "_" + paras.getTerminal();
        }
        if (caches.containsKey(key)) {
            return caches.get(key);
        }

        Map<String, Object> where = new HashMap<String, Object>();
        where.put("styleId:=", id);
        Map<String, Integer> order = new HashMap<String, Integer>();
        order.put("order", 0);
        List<MapStyleEntity> styleEntitys = dao.getEntitys(where, order);
        if (null == styleEntitys || styleEntitys.size() < 1) {
            ResponseEntity<String> obj = new ResponseEntity<>();
            obj.setCode("-1");
            obj.setMsg("未找到匹配方案");
            throw new RuntimeException(obj.toString());
        } else {
            MapStyleEntity styleEntity = styleEntitys.get(0);
            MapStyle result = convert(styleEntity);
            caches.put(key, result);
            return result;
        }
    }

    /**
     * 条件下删除
     */
    @Override
    public void deletes(Map<String, Object> where) {
        // 配置事务策略
        DefaultTransactionDefinition def = new DefaultTransactionDefinition();
        def.setName("planOne-transaction");
        def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
        // 设置状态点
        TransactionStatus status = transactionManager.getTransaction(def);
        try {
            List<MapStyleEntity> entitys = this.getEntitys(where, null);
            for (MapStyleEntity entity : entitys) {
                this.delete(entity.getId());
            }
        } catch (Exception e) {
            transactionManager.rollback(status);
            throw e;
        }
        transactionManager.commit(status);
    }

    @Override
    public Boolean delete(String id) {
        // 配置事务策略
        DefaultTransactionDefinition def = new DefaultTransactionDefinition();
        def.setName("planOne-transaction");
        def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
        // 设置状态点
        TransactionStatus status = transactionManager.getTransaction(def);
        Boolean result = false;
        try {
            result = super.delete(id);
            // 删除字典服务
            Map<String, Object> where = new HashMap<>();
            where.put("styleId", id);
            layerDao.deletes(where);
            sourceDao.deletes(where);
            configVersionService.addVersion();
        } catch (Exception e) {
            transactionManager.rollback(status);
            throw e;
        }
        transactionManager.commit(status);
        return result;
    }

    /**
     * 添加实体
     *
     * @param entity 添加实体
     * @return
     */
    @Override
    public MapStyleEntity add(MapStyleEntity entity) {
        configVersionService.addVersion();
        caches.clear();
        return super.add(entity);
    }

    /**
     * 更新实体
     *
     * @param guid   唯一值
     * @param entity 实体
     * @return
     */
    @Override
    public MapStyleEntity update(MapStyleEntity entity) {
        configVersionService.addVersion();
        caches.clear();
        return super.update(entity);
    }

    /**
     * 指量删除实体
     *
     * @param guid 唯一值集
     */
    @Override
    public Boolean deletes(String guids) {
        configVersionService.addVersion();
        caches.clear();
        return super.deletes(guids);
    }

    /**
     * 逻辑删除恢复
     *
     * @param guid
     */
    @Override
    public Boolean reply(String guid) {
        configVersionService.addVersion();
        caches.clear();
        return super.reply(guid);
    }

    /**
     * 导入Excel数据
     *
     * @param fileNmae   文件名
     * @param fileStream 数据文件
     * @param inputID    导入配置
     * @param startrow   开始导入行
     * @return
     */
    @Override
    public DataInputResult input(String fileName, InputStream fileStream, String inputID, Integer startrow) {
        configVersionService.addVersion();
        caches.clear();
        return super.input(fileName, fileStream, inputID, startrow);
    }

    /**
     * 导入Shape数据
     *
     * @param fileNmae 文件名
     * @return
     */
    @Override
    public DataInputResult importShape(String fileName, String inputID) {
        configVersionService.addVersion();
        caches.clear();
        return super.importShape(fileName, inputID);
    }

    protected MapStyle convert(MapStyleEntity entity) {
        MapStyle toEntity = new MapStyle();
        BeanUtils.copyProperties(entity, toEntity,
                "sources", "layers");
        if (entity.getSources() != null && entity.getSources().size() > 0) {
            toEntity.setSources(new LinkedHashSet<>());
            for (MapStyleSourceEntity item : entity.getSources()) {
                MapStyleSource source = new MapStyleSource();
                BeanUtils.copyProperties(item, source);
                toEntity.getSources().add(source);
            }
        }

        if (entity.getLayers() != null && entity.getLayers().size() > 0) {
            toEntity.setLayers(new LinkedHashSet<>());
            for (MapStyleLayerEntity item : entity.getLayers()) {
                MapStyleLayer layer = new MapStyleLayer();
                BeanUtils.copyProperties(item, layer);
                toEntity.getLayers().add(layer);
            }
        }

        return toEntity;
    }
}
